package com.hddz.comlib;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;

import com.android.uhflibs.as3992_native;
import com.hddz.comlib.packet.RFIDPacketReceiver;

public class As3992demoISO6CHeper {
	/** Called when the activity is first created. */
	private static final String[] list = { "Reserved", "EPC", "TID", "USER" };
	private static final String TAG = "As3992demoISO6CHeper";
	private as3992_native native_method;
	private DeviceControlAs3992 mdevCtrl;
	private ReadThread mReadThread;
	private String current_tag_epc = null;

	private PowerManager pM = null;

	private WakeLock wK = null;

	private int init_progress = 0;
	private Boolean isStop = false;

	private static final String DEVFILE_PATH = "/sys/class/misc/mtgpio/pin";
	private static final String SERIALPORT_PATH = "/dev/ttyMT2";
	private RFIDPacketReceiver packetReceiver;
	private List<EpcDataBase> firm = new ArrayList<EpcDataBase>();
	private SearchThread mSearchThread;
	private Boolean isRunning = false;

	public void setPacketReceiver(RFIDPacketReceiver packetReceiver) {
		this.packetReceiver = packetReceiver;
	}

	public Boolean startRFIDSerial(Context context) {
		isStop = false;
		isRunning = true;
		try {
			Log.d(TAG, "startRFIDSerial");

			native_method = new as3992_native();
			if (native_method.OpenComPort(SERIALPORT_PATH) != 0) {
				return false;
			}

			mReadThread = new ReadThread();
			mdevCtrl = new DeviceControlAs3992(DEVFILE_PATH);

			mdevCtrl.PowerOnDevice();
			if (mReadThread.isInterrupted()) {
				mReadThread.resume();
			} else {
				mReadThread.start();
			}
			// =====================================
			pM = (PowerManager) context.getSystemService(android.content.Context.POWER_SERVICE);
			if (pM != null) {
				wK = pM.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, "lock3992");
				if (wK != null) {
					wK.acquire();
					init_progress++;
				}
			}

			if (init_progress == 2) {
				Log.w("3992_6C", "wake lock init failed");
			}

			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			byte[] soft_ver = native_method.get_version(0);

			native_method.set_gen2(0, (byte) 6);
			native_method.set_gen2(1, (byte) 1);
			native_method.set_gen2(3, (byte) 1);
			set_sensitivity(-72);
			set_hopping_freq(920625, 924375, 750, -40);
			native_method.set_alloc_param(1, 10000, 0);
			try {
				if (mSearchThread != null) {
					Log.d(TAG, "SearchThread not kill");
					mSearchThread.interrupt();
					Thread.sleep(200);
					mSearchThread = null;
				}
			} catch (Exception ex) {
				Log.d(TAG, "SearchThread kill error");
			}
			mSearchThread = new SearchThread();
			power_antenna(true);
			mSearchThread.start();
			return true;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
	}

	public Boolean stopRFIDSerial() {
		isRunning = false;
		if (isStop) {
			return true;
		}
		try {
			Log.d(TAG, "stopRFIDSerial");

			if (mReadThread != null) {
				mReadThread.interrupt();
				Thread.sleep(200);
				mReadThread = null;
			}

			if (mSearchThread != null) {
				Log.d(TAG, "SearchThread kill");
				mSearchThread.interrupt();
				Thread.sleep(200);
				mSearchThread = null;
			}
			if (mdevCtrl != null) {
				mdevCtrl.PowerOffDevice();
				mdevCtrl = null;
			}
			power_antenna(false);
			native_method.CloseComPort();
			isStop = true;
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	private void receivedCNT(List<EpcDataBase> epcs) {
		Log.d(TAG, "Read RFID:" + epcs);
		if (packetReceiver != null) {
			packetReceiver.OnReceivedEPCS(epcs);
		}
	}

	public class EpcDataBase {
		String epc;
		int valid;

		public EpcDataBase(String e, int v) {
			// TODO Auto-generated constructor stub
			epc = e;
			valid = v;
		}

		@Override
		public String toString() {
			return epc;
		}
	}

	class SearchThread extends Thread {
		private String epcs[] = null;

		@Override
		public void run() {
			super.run();
			Log.d(TAG, " SearchThread run start");
			while (!isInterrupted() && isRunning) {
				Log.d(TAG, "SearchThread running");
				epcs = search_UHF();
				if (epcs != null) {
					String tmp[] = epcs;
					int i, j;
					for (i = 0; i < tmp.length; i++) {
						for (j = 0; j < firm.size(); j++) {
							if (tmp[i].equals(firm.get(j).epc)) {
								firm.get(j).valid = 5;
								break;
							}
						}
						if (j == firm.size()) {
							firm.add(new EpcDataBase(tmp[i], 5));
						}
					}
					for (i = 0; i < firm.size(); i++) {
						for (j = 0; j < tmp.length; j++) {
							if (firm.get(i).epc.equals(tmp[j])) {
								break;
							}
						}
						if (j == tmp.length) {
							if (--firm.get(i).valid == 0) {
								firm.remove(i);
							}
						}
					}
				} else {
					for (int i = 0; i < firm.size(); i++) {
						if (--firm.get(i).valid == 0) {
							firm.remove(i);
						}
					}
				}

				if (firm.size() > 0) {
					receivedCNT(firm);
				}

				try {
					sleep(200);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					this.interrupt();
				}
			}
			Log.d(TAG, "SearchThread run stop");
		}
	}

	class ReadThread extends Thread {
		@Override
		public void run() {
			super.run();
			while (!isInterrupted() && isRunning) {
				native_method.read_thread();
			}
		}
	}

	as3992_native.Freq_Msg get_hopping_freq() {
		int retry = 0;
		as3992_native.Freq_Msg res;
		while ((res = native_method.get_freq()) == null) {
			Log.e("as3992", "get freq retry");
			if ((++retry) >= 5) {
				return null;
			}
		}
		return res;
	}

	String[] search_UHF() {
		List<as3992_native.Tag_Data_Rssi> cnt;
		int retry = 0;
		do {
			// Log.e("as3992", "search retry");
			cnt = native_method.search_card_rssi();
			if ((++retry) >= 10) {
				return null;
			}
		} while (cnt == null);
		int noc = cnt.size();
		String[] out = new String[noc];
		for (int i = 0; i < noc; i++) {
			out[i] = new String();
			int loe = cnt.get(i).tdata.epc.length;
			for (int j = 0; j < loe; j++) {
				out[i] += String.format("%02x ", cnt.get(i).tdata.epc[j]);
			}
		}
		return out;
	}

	int select_UHF(String epc) {
		StringTokenizer sepc = new StringTokenizer(epc);
		byte[] eepc = new byte[sepc.countTokens()];
		int index = 0;
		while (sepc.hasMoreTokens()) {
			try {
				eepc[index++] = (byte) Integer.parseInt(sepc.nextToken(), 16);
			} catch (NumberFormatException p) {
				return -1;
			}
		}
		int retry = 0;
		do {
			Log.e("as3992", "select retry");
			if ((++retry) >= 10) {
				return -1;
			}
		} while (native_method.select_card(eepc) != 0);
		return 0;
	}

	int get_sensitivity() {
		int retry = 0, reval;
		// while((reval = get_sens()) == 100)
		while ((reval = native_method.get_gen2(5)) == 1000) {
			Log.e("as3992", "getsens retry");
			if ((++retry) >= 5) {
				return 1000;
			}
		}
		Log.i("as3992_spec", "" + reval);
		return reval;
	}

	int set_sensitivity(int sens) {
		int retry = 0;
		Log.i("as3992_spec", "" + sens);
		// while(set_sens(sens) != 0)
		while (native_method.set_gen2(5, (byte) sens) != 0) {
			Log.e("as9932", "setsens retry");
			if ((++retry) >= 5) {
				return -1;
			}
		}
		return 0;
	}

	int power_antenna(boolean power) {
		int retry = 0;
		while (native_method.set_antenna_power(power) != 0) {
			Log.e("as3992", "set antenna power " + power + " retry");
			if ((++retry) >= 5) {
				return -1;
			}
		}
		return 0;
	}

	int select_once(String epc) {
		StringTokenizer sepc = new StringTokenizer(epc);
		byte[] eepc = new byte[sepc.countTokens()];
		int index = 0;
		while (sepc.hasMoreTokens()) {
			try {
				eepc[index++] = (byte) Integer.parseInt(sepc.nextToken(), 16);
			} catch (NumberFormatException p) {
				Log.e("as3992", "error prase number");
				return -1;
			}
		}
		return native_method.select_card(eepc);

	}

	String read_card(String epc, int area, int addr, int count) {

		byte[] res = null;
		int retry = 0;// , reval = 0;
		do {
			if (retry != 0) {
				Log.e("as3992", "read retry");
			}
			if ((++retry) >= 10) {
				return null;
			}
			if (select_once(epc) < 0) {
				Log.e("as3992", "read select failed");
				continue;
			}
			// res = read_area(area, addr, count);
			res = native_method.read_area(area, addr, count);
		} while (res == null);
		String out = new String();
		for (int i = 0; i < res.length; i++) {
			out += String.format("%02x ", res[i]);
		}
		return out;
	}

	int write_card(String epc, int area, int addr, int count, String passwd, String content) {
		Log.i("as3992", passwd);
		Log.i("as3992", content);
		byte[] pasw = new byte[4];
		byte[] cont = new byte[count * 2];
		StringTokenizer ps = new StringTokenizer(passwd);
		if (ps.countTokens() != 4) {
			return -2;
		}
		StringTokenizer cn = new StringTokenizer(content);
		if (cn.countTokens() != count * 2) {
			return -3;
		}
		int index = 0;
		while (ps.hasMoreTokens()) {
			try {
				pasw[index++] = (byte) Integer.parseInt(ps.nextToken(), 16);
			} catch (NumberFormatException p) {
				return -4;
			}
		}
		index = 0;
		while (cn.hasMoreTokens()) {
			try {
				cont[index++] = (byte) Integer.parseInt(cn.nextToken(), 16);
			} catch (NumberFormatException p) {
				return -4;
			}
		}
		int retry = 0, writed = 0, reval;
		// while(write_area(area, addr, count, pasw, cont) != 0)
		// while(native_method.write_area(area, addr, count, pasw, cont) != 0)
		do {
			if (retry != 0) {
				Log.e("as3992", "write retry " + writed + " words writed");
			}
			if ((++retry) >= 5) {
				return -1;
			}
			if (select_once(epc) < 0) {
				Log.e("as3992", "write select error");
				continue;
			}
			reval = native_method.write_area(area, addr + writed, count - writed, pasw, cont);
			if (reval > 0) {
				if (reval == (count - writed)) {
					break;
				}
				writed += reval;
				byte[] tp = new byte[(count - writed) * 2];
				System.arraycopy(cont, reval * 2, tp, 0, tp.length);
				cont = tp;
			}
		} while (writed < count);
		/*
		 * while((reval = native_method.write_area(area, addr + writed, count -
		 * writed, pasw, cont)) < (count - writed)) { if(reval >= 0) { writed +=
		 * reval; byte[] tp = new byte[(count - writed) * 2];
		 * System.arraycopy(cont, writed * 2, tp, 0, tp.length); cont = tp;
		 * if(writed == count) { break; } } Log.e("as3992", "write retry " +
		 * writed + " words writed"); if((++retry) >= 10) { return -1; } }
		 */
		return 0;
	}

	int set_EPC(String epc, int epclength, String passwd, String EPC) {
		byte[] res;
		int retry = 0;
		do {
			Log.e("as3992", "read retry");
			res = native_method.read_area(1, 1, 1);
			if ((++retry) >= 10) {
				return -5;
			}
		} while (res == null);
		res[0] = (byte) ((res[0] & 0x7) | (epclength << 3));
		String PC = String.format("%02x ", res[0]) + " " + String.format("%02x ", res[1]) + " ";
		Log.d("as3992", "new epc value is " + PC + EPC);
		return write_card(epc, 1, 1, 7, passwd, PC + EPC);
	}

	int set_Password(String epc, int which, String cur_pass, String new_pass) {
		if (which > 1 || which < 0) {
			return -5;
		}
		return write_card(epc, 0, which * 2, 2, cur_pass, new_pass);
	}

	int lock_Card(String epc, int area, int type, String passwd) {
		byte[] pasw = new byte[4];
		StringTokenizer ps = new StringTokenizer(passwd);
		if (ps.countTokens() != 4) {
			return -3;
		}
		int index = 0;
		while (ps.hasMoreTokens()) {
			try {
				pasw[index++] = (byte) Integer.parseInt(ps.nextToken(), 16);
			} catch (NumberFormatException p) {
				return -2;
			}
		}
		int retry = 0, reval = -1;
		do {
			if (retry != 0) {
				Log.e("as3992", "lock retry");
			}
			if ((++retry) >= 10) {
				return -1;
			}
			if (select_once(epc) < 0) {
				Log.e("as3992", "lock select error");
				continue;
			}
			reval = native_method.setlock((byte) type, (byte) area, pasw);
		} while (reval < 0);
		/*
		 * while(native_method.setlock((byte)type, (byte)area, pasw) != 0) {
		 * Log.e("as3992", "lock retry"); if((++retry) >= 10) { return -1; } }
		 */
		return 0;
	}

	int kill_Card(String epc, String passwd) {
		byte[] pasw = new byte[4];
		StringTokenizer ps = new StringTokenizer(passwd);
		if (ps.countTokens() != 4) {
			return -3;
		}
		int index = 0;
		while (ps.hasMoreTokens()) {
			try {
				pasw[index++] = (byte) Integer.parseInt(ps.nextToken(), 16);
			} catch (NumberFormatException p) {
				return -2;
			}
		}
		int retry = 0, reval = -1;
		do {
			if (retry != 0) {
				Log.e("as3992", "kill retry");
			}
			if ((++retry) >= 10) {
				return -1;
			}
			if (select_once(epc) < 0) {
				Log.e("as3992", "kill select error");
				continue;
			}
			reval = native_method.setkill(pasw, (byte) 0);
		} while (reval < 0);
		/*
		 * while(native_method.setkill(pasw, (byte)0) != 0) //class-1 card don't
		 * need recom, set it to 0 { Log.e("as3992", "kill retry"); if((++retry)
		 * >= 10) { return -1; } }
		 */
		return 0;
	}

	int set_hopping_freq(int start, int stop, int increment, int rssi)// , int
																		// id)
																		// //in
																		// my
																		// gui
																		// program
																		// don't
																		// use
																		// profile
																		// id.
																		// Just
																		// set
																		// it to
																		// zero.
	{
		int retry = 0, reval;
		while ((reval = native_method.set_freq(start, stop, increment, rssi, 0)) != 0) {
			if (reval == -2) {
				return -2;
			}
			Log.e("as9932", "setfreq retry");
			if ((++retry) >= 5) {
				return -1;
			}
		}
		return 0;
	}

	int get_level() {
		int retry = 0;
		byte[] res;
		while ((res = native_method.get_reg(0x15)) == null) {
			Log.e("as3992", "read 0x15 failed");
			if ((++retry) >= 5) {
				return 100;
			}
		}
		if (res.length < 3) {
			Log.e("as3992", "read 0x15 don't get enough data");
			return 100;
		}
		Log.d("as3992", "read 0x15 reg ok " + res[0] + " " + res[1] + " " + res[2]);
		int coarse = (res[0] & 0x18) >> 3;
		int fine = res[0] & 0x7;
		return -coarse * 6 - fine;
	}

	int set_level(int level) {
		byte val, mtlc = 0, mtlf;
		int v, retry = 0;
		byte[] res;
		while ((res = native_method.get_reg(0x15)) == null) {
			Log.e("as3992", "read 0x15 failed");
			if ((++retry) >= 5) {
				return -1;
			}
		}
		if (res.length < 3) {
			Log.e("as3992", "read 0x15 don't get enough data");
			return -1;
		}
		v = level;
		if (level <= -12) {
			v += 12;
			mtlc = 2;
		} else if (level <= -6) {
			v += 6;
			mtlc = 1;
		}
		mtlf = (byte) -v;

		val = res[0];
		val = (byte) (val & 0xe0);
		val = (byte) (val | mtlc << 3 | mtlf);

		byte[] write_buf = new byte[3];
		write_buf[0] = val;
		write_buf[1] = res[1];
		write_buf[2] = res[2];
		retry = 0;
		while (native_method.set_reg(0x15, write_buf) < 0) {
			Log.e("as3992", "write to write 0x15 failed");
			if ((++retry) >= 5) {
				return -1;
			}
		}
		return 0;
	}
}